package ci.web.codec;

import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.FileUpload;
import io.netty.handler.codec.http.multipart.HttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * 普通HTTP_POST数据解码器
 * @author zhh
 */
public class FormPostDecoder {

	/**
	 * 解码HTTP_POST数据工厂<br/>
	 * 文件使用磁盘，参数使用内存
	 */
	private static HttpDataFactory _httpDataFactory = new WebHttpDataFactory(true);
	public static HttpDataFactory httpDataFactory(){
		return _httpDataFactory;
	}
	public static void httpDataFactory(HttpDataFactory factory){
		if(_httpDataFactory==factory || factory==null)return;
		_httpDataFactory.cleanAllHttpData();
		_httpDataFactory = factory;
	}
	
	protected static final List<FileItem> EMPTY_FILES = new ZeroList<FileItem>(0);
	protected static final List<InterfaceHttpData> EMPTY_BODYDATAS = new ZeroList<InterfaceHttpData>(0);
	
	protected List<InterfaceHttpData> bodyDatas;
	protected JSONObject paramters;
	protected List<FileItem> files;
	protected final FullHttpRequest request;
	
	public FormPostDecoder(FullHttpRequest request) throws Exception {
	    this(request, true);
	}
	public FormPostDecoder(FullHttpRequest request, boolean decode) throws Exception {
		this.request = request;
		if(decode){
		    decode();
		}
	}

	protected void decode() throws Exception{
		paramters = new JSONObject();
		bodyDatas = decodeHttpPostData(request, paramters);
	}
	
	/**
	 * 请求中post的body数据
	 * @return
	 * @throws Exception
	 */
	public List<InterfaceHttpData> bodyDatas()throws Exception {
		if(bodyDatas==null){
			try {
				decode();
			} catch (Exception e) {
				bodyDatas = new ArrayList<InterfaceHttpData>(0);
				throw e;
			}
		}
		return bodyDatas;
	}
	/**
	 * request-paramters
	 * @return
	 */
	public JSONObject paramters(){
		if(paramters==null){
			try {
				decode();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		return paramters;
	}
	/**
	 * request-files
	 * @return
	 */
	public List<FileItem> files(){
		if(files==null){
			try {
				files = filterFileUpLoad(bodyDatas());
			} catch (Exception e) {
			    throw new RuntimeException(e);
			}
		}
		return files;
	}
	/**
	 * request-file
	 * @param name
	 * @return
	 */
	public FileItem getFile(String name){
	    List<FileItem> arr = files();
	    for(FileItem item : arr){
	        if(item.getName()==name){
	            return item;
	        }
	    }
	    return null;
	}
	/**
	 * request-file-first
	 * @return
	 */
	public FileItem getFile(){
	    List<FileItem> arr = files();
	    if(arr.size()>0){
	        return arr.get(0);
	    }
	    return null;
	}
	/**
	 * 删除所有上传来的临时文件
	 */
    public void clean() {
        httpDataFactory().cleanRequestHttpData(request);
        if(files != null){
            for (FileItem item : files) {
                item.delete();
            }
        }
    }
	
	//decode-form
	public static List<InterfaceHttpData> decodeHttpPostData(FullHttpRequest request, JSONObject paramter) throws IOException{
		return decodeHttpPostData(request, paramter, null);
	}
	//decode-form
	public static List<InterfaceHttpData> decodeHttpPostData(FullHttpRequest request, List<FileItem> files) throws IOException{
		return decodeHttpPostData(request, null, files);
	}
	//decode-form
	public static List<InterfaceHttpData> decodeHttpPostData(FullHttpRequest request, JSONObject paramter, List<FileItem> files) throws IOException{
		HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(httpDataFactory(), request);
        List<InterfaceHttpData> list = decoder.getBodyHttpDatas();
        for(InterfaceHttpData data : list){
//        	System.out.println(data.getName() + ", "+data.getHttpDataType());
        	if(data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute){
        		if(paramter==null) continue;
        		Attribute attribute = (Attribute)data;
        		String key = attribute.getName();
        		if(key.endsWith("[]") && key.length()>2){
        		    if(paramter.containsKey(key)==false){
        		        JSONArray arr = new JSONArray(2);
        		        arr.add(attribute.getValue());
        		        paramter.put(key, arr);
        		    }else{
        		        JSONArray arr = paramter.getJSONArray(key);
        		        arr.add(attribute.getValue());
        		    }
        		}else{
        		    paramter.put(attribute.getName(), attribute.getValue());
        		}
        	}else if(files!=null && data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload){
//        		FileUpload fileUpload = (FileUpload)data;
//        		if(fileUpload.isInMemory()==false)files.add(fileUpload);
        	    files.add(new FileItem((FileUpload)data));
        	}
        }
        return list;
	}
	//decode-form-file
	public static List<FileItem> filterFileUpLoad(List<InterfaceHttpData> postData){
		List<FileItem> files = new ArrayList<FileItem>(0);
		for(InterfaceHttpData data : postData){
			if(data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload){
//				FileUpload fileUpload = (FileUpload)data;
//        		if(fileUpload.isInMemory()==false)files.add(fileUpload);
				files.add(new FileItem((FileUpload)data));
			}
		}
		return files;
	}
	
}
